﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using Commands.TorrentDownloaders;

namespace Commands.Commands
{
    internal static class CommandsLoader
    {
        public static MethodsManager CreateMethodsManager(
            IMailer mailer, ITorrentManager torrentManager, ICommandManager manager, string pluginsFolder)
        {
            var allCommands = new List<CommandListBase>();
            allCommands.Add(new InternalCommands(mailer));
            allCommands.Add(new CommandsList(mailer, torrentManager));

            // In case if we have plugins settings.
            if(!string.IsNullOrEmpty(pluginsFolder))
                allCommands.AddRange(_GetExternalComands(mailer, torrentManager, pluginsFolder));

            
            return new MethodsManager(allCommands, manager);
        }

        private static IEnumerable<CommandListBase> _GetExternalComands(
            IMailer mailer, ITorrentManager manager, string externalAssembliesDirectory)
        {
            var result = new List<CommandListBase>();

            if (!Directory.Exists(externalAssembliesDirectory))
                return result;

            string[] files = System.IO.Directory.GetFiles(externalAssembliesDirectory, EXTERNAL_LIB_EXTENSION);

            foreach (var file in files)
            {
                // TODO  Load, LoadFile?
                var assembly = Assembly.LoadFrom(file);

                Type[] types = assembly.GetExportedTypes();

                foreach (var type in types)
                {
                    if (typeof(CommandListBase).IsAssignableFrom(type))
                    {
                        try
                        {
                            result.Add(_CreateCommandsList(type, mailer, manager));
                        }
                        // If we have problem with constructing - log it and resume.
                        catch (Exception ex)
                        {
                        }
                    }
                }
            }

            return result;
        }

        private static CommandListBase _CreateCommandsList(Type type, IMailer mailer, ITorrentManager manager)
        {
            var constructors = type.GetConstructors();

            // TOOD select proper constructor?
            var constructor = constructors.First();
            //foreach (var constructorInfo in constructors)
            //{
            //    if(constructorInfo.GetParameters
            //}

            var parameters = new List<object>();
            foreach (var methodParameterInfo in constructor.GetParameters())
            {
                if (methodParameterInfo.ParameterType == typeof(IMailer))
                    parameters.Add(mailer);
                else if (methodParameterInfo.ParameterType == typeof(ITorrentManager))
                    parameters.Add(manager);
                else
                    Debug.Assert(false, "New internal parameter type was added.");
            }

            var obj = (CommandListBase)constructor.Invoke(parameters.ToArray());

            var properties = type.GetProperties();
            foreach (var property in properties)
            {
                if (property.PropertyType == typeof(IMailer))
                    property.SetValue(obj, mailer, null);
                else if (property.PropertyType == typeof(ITorrentManager))
                    property.SetValue(obj, manager, null);
                else
                    Debug.Assert(false, "New property type has been added.");
            }

            return obj;
        }

        private const string EXTERNAL_LIB_EXTENSION = "*.dll";
    }
}
